#include "laser.h"
#include "utils.h"
#include "coord.h"
#include "csbmath.h"


#ifdef __cplusplus
extern "C" {
#endif
	/*********************| 内部数据定义 |*********************/
	/* 激光事件控制变量名 */
#define LS_CON_T_NowFme	0	//当前帧
#define LS_CON_T_X	1	//X坐标
#define LS_CON_T_Y	2	//Y坐标
#define LS_CON_T_r	3	//半径
#define LS_CON_T_RV	4	//半径方向
#define LS_CON_T_Muzzle	5	//条数
#define LS_CON_T_Freq	6	//周期
#define LS_CON_T_Angle	7	//角度
#define LS_CON_T_Range	8	//范围
#define LS_CON_T_WS	9	//宽比
#define LS_CON_T_HS	10	//高比
#define LS_CON_T_Alpha	11	//不透明度
#define LS_CON_T_StartX	12	//启用射线激光
	/* 激光事件结束 */
	// 常规事件
#define LS_RES_T_X	0	//X坐标
#define LS_RES_T_Y	1	//Y坐标
#define LS_RES_T_r	2	//半径
#define LS_RES_T_rV	3	//半径方向
#define LS_RES_T_Muzzle	4	//条数
#define LS_RES_T_Freq	5	//周期
#define LS_RES_T_Angle	6	//角度
#define LS_RES_T_Range	7	//范围
#define LS_RES_T_v	8	//速度
#define LS_RES_T_vV	9	//速度方向
#define LS_RES_T_va	10	//加速度
#define LS_RES_T_vaV	11	//加速度方向
	/* 从这里开始才是子弹有的 */
#define LS_OBJ_BULLET_ACTION_BOUNDARY	12
#define LS_RES_BT_life	12	//生命
#define LS_RES_BT_ID	13	//类型
#define LS_RES_BT_WS	14	//宽比
#define LS_RES_BT_HS	15	//高比
#define LS_RES_BT_Alpha	16	//不透明度
#define LS_RES_BT_StartX	17	//不透明度
#define LS_RES_BT_v	18	//子弹速度
#define LS_RES_BT_vV	19	//子弹速度方向
#define LS_RES_BT_va	20	//子弹加速度
#define LS_RES_BT_vaV	21	//子弹加速度方向
#define LS_RES_BT_VHS	22	//横比
#define LS_RES_BT_VWS	23	//纵比
#define LS_RES_ET_Light	24	//高光效果
#define LS_RES_ET_OutSc	25	//出屏即消
#define LS_RES_ET_Invin	26	//无敌状态

/*********************| marcos |*********************/
	CS_BUF_DECLAR(LASER_BULLET_BUF_SIZE, laserbu_t)
		CS_BUF_DECLAR(LASER_BUF_SIZE, laser_t)


	static bool ls_action_match(const int8_t t, const int8_t s, const int d,
		const csnode_t* pcs)
	{
		laser_t* pem = (laser_t*)pcs->pobj;
		switch (t) {
		case LS_CON_T_NowFme:
			return action_con_match(pem->obj.life, s, d);
		case LS_CON_T_X:
			return action_con_match(pem->obj.ele.pos.x, s, d);
		case LS_CON_T_Y:
			return action_con_match(pem->obj.ele.pos.y, s, d);
		case LS_CON_T_r:
			return action_con_match(pem->obj.emitedge.r, s, d);
		case LS_CON_T_RV:
			return action_con_match(pem->obj.emitedge.angle, s, d);
		case LS_CON_T_Muzzle:
			return action_con_match(pem->obj.nmuzzle, s, d);
		case LS_CON_T_Freq:
			return action_con_match(pem->obj.freq, s, d);
		case LS_CON_T_Angle:
			return action_con_match(pem->obj.rotateOffset, s, d);
		case LS_CON_T_Range:
			return action_con_match(pem->obj.emitRange, s, d);
		case LS_CON_T_WS:
			return action_con_match(pem->buScale.xs, s, d);
		case LS_CON_T_HS:
			return action_con_match(pem->buScale.ys, s, d);
		//case LS_CON_T_Alpha:
		//	return action_con_match(pem->bucolor.A, s, d);
			//	case LS_CON_T_Opdir :
			//	NOTE:朝向暂时被顾略
		default:
			return false;
		}
	}

#define CTL_LESS0_E0(_d_, _tmp_, _eff_) \
	_tmp_ = action_res2(_d_, _eff_->ressign,_eff_->data);\
	if (_tmp_ < 0) _d_ = 0;\
	else _d_ = tmp;\
	return

#define CTL_EFFECT_BY_RES_DATA(effect, mask, eff) \
	if (!eff->n) {\
		if (eff->data) { effect = CSB_FLAG_ON(effect, mask); }\
		else { effect = CSB_FLAG_OFF(effect, mask); }\
	}\
	return

#define CTL_COLOR_RES_DATA(_d_, _tmp_, _eff_) \
	_tmp_ = action_res2(_d_, _eff_->ressign, _eff_->data);\
	if (_tmp_ < 0) { _d_ = 0;} \
	else if (_tmp_ > 255) { _d_ = 255;}\
	else { _d_= _tmp_;}\
	return

	CSB_DLL void laser_2origin(const laserdata_t * pdata, laser_t* pem, bool freeaction)
	{
		CSB_NO_VRET(pdata && pem);
		pem->obj.ele.flag = 0;
		/**	pem->obj.ele.pos = pdata->emitpos;
		if (AUTO_SELF == pdata->emitpos.x) {
		pem->obj.ele.flag |= X_AM;
		}
		if (AUTO_SELF == pdata->emitpos.y) {
		pem->obj.ele.flag |= Y_AM;
		}
		**/
		if (AUTO_SELF == pdata->objtag.angle) {
			pem->obj.ele.flag |= R_AM;
			pem->obj.rotateOffset = 0;
		}
		else {
			pem->obj.rotateOffset = pdata->objtag.angle;
		}
		pem->obj.ele.scale.xs = pem->obj.ele.scale.ys = 1.0f;
		pem->buScale = pdata->bullet.b.scale;

		pem->obj.emitRange = pdata->objtag.emitrange;
		pem->obj.freq = pdata->objtag.freq;
		pem->obj.nmuzzle = pdata->objtag.nmuzzle;
		pem->obj.emitedge = pdata->objtag.emitedge;
		pem->obj.v = pdata->objtag.v;
		pem->obj.va = pdata->objtag.va;

		pem->buattr.ID = pdata->bullet.b.ID;
		pem->buattr.v.v = pdata->bullet.b.v;
		pem->buattr.v.dir = pdata->objtag.angle;
		pem->buattr.lifetime = pdata->bullet.b.life;
		pem->buattr.life = 0;
		pem->buattr.va = pdata->bullet.b.va;

		if (AUTO_SELF == pem->buattr.va.dir) {
			pem->obj.ele.flag |= RB_AM;
		}
		//pem->buattr.vRate = pdata->bullet.vRate;
		pem->bueffect = pdata->bullet.effect;
		pem->obj.ele.rotate = CSB_FLAG_TEST(pem->bueffect, BU_EFF_Face2V) ? pdata->objtag.angle : 0;
		if (freeaction) {
			ac_free(pem->aclist);
		}
		pem->aclist = ac_buf_copy(pdata->aclist);
	}

#define RES_TO_ME_DRATIO(_eff_, _d_)  \
	_eff_->data = (_eff_->data - _d_) / _eff_->n; \
	return true

	// 处理发射器自身的事件
	static bool 	laser_ac_for(action_t* pac, void* flag)
	{
		csnode_t* pcs = (csnode_t*)flag;
		// 判定条件是否触发
		bool b1 = ls_action_match(CON_GET_TYPE1(pac->con.tAs), CON_GET_SIGN1(pac->con.tAs), pac->con.data0, pcs);
		bool b2 = true;
		const int8_t aor = CON_GET_AOR(pac->con.tAs);
		if (CON_SIGN_TRUE != aor) {
			b2 = ls_action_match(CON_GET_TYPE2(pac->con.tAs), CON_GET_SIGN2(pac->con.tAs), pac->con.data1, pcs);
		}
		if (!action_2con_match(b1, b2, aor))
			return false;
		laser_t* pem = (laser_t*)pcs->pobj;
		action_eff_t* eff = action_make_action_eff(pac);
		CSB_NO_RET(eff, true);
		list_insert(&pcs->pobj->ac_eff_list, (void*)eff, 0, 0);
		// 如果是正比且变化符号是变化到，那么就需要转换成增量处理
		CSB_NO_RET(CON_RES_TO == eff->ressign && CON_ME_DRATIO == eff->mesign, true);
		eff->ressign = CON_RES_ADD;
		switch (eff->type) {
		case LS_RES_ET_Light:
		case LS_RES_ET_OutSc:
		case LS_RES_ET_Invin:
			return true;
			// 常规事件
		case LS_RES_T_X:
			RES_TO_ME_DRATIO(eff, pem->obj.ele.pos.x);
		case LS_RES_T_Y:
			RES_TO_ME_DRATIO(eff, pem->obj.ele.pos.y);
		case LS_RES_T_r:
			RES_TO_ME_DRATIO(eff, pem->obj.emitedge.r);
		case LS_RES_T_rV:
			RES_TO_ME_DRATIO(eff, pem->obj.emitedge.angle);
		case LS_RES_T_Muzzle:
			RES_TO_ME_DRATIO(eff, pem->obj.nmuzzle);
		case LS_RES_T_Freq:
			RES_TO_ME_DRATIO(eff, pem->obj.freq);
		case LS_RES_T_Angle:
			RES_TO_ME_DRATIO(eff, pem->obj.rotateOffset);
		case LS_RES_T_Range:
			RES_TO_ME_DRATIO(eff, pem->obj.emitRange);
		case LS_RES_T_v:
			RES_TO_ME_DRATIO(eff, pem->obj.v.v);
		case LS_RES_T_vV:
			RES_TO_ME_DRATIO(eff, pem->obj.v.dir);
		case LS_RES_T_va:
			RES_TO_ME_DRATIO(eff, pem->obj.va.v);
		case LS_RES_T_vaV:
			RES_TO_ME_DRATIO(eff, pem->obj.va.dir);
		case LS_RES_BT_life:
			RES_TO_ME_DRATIO(eff, pem->buattr.lifetime);
		case LS_RES_BT_ID:
			RES_TO_ME_DRATIO(eff, pem->buattr.ID);
		case LS_RES_BT_WS:
			RES_TO_ME_DRATIO(eff, pem->buScale.xs);
		case LS_RES_BT_HS:
			RES_TO_ME_DRATIO(eff, pem->buScale.ys);
			//case LS_RES_BT_Alpha:
			//	RES_TO_ME_DRATIO(eff, pem->bucolor.A);
			//	case LS_RES_T_Opdir:NOTE:朝向暂时不支持
		case LS_RES_BT_v:
			RES_TO_ME_DRATIO(eff, pem->buattr.v.v);
		case LS_RES_BT_vV:
			RES_TO_ME_DRATIO(eff, pem->buattr.v.dir);
		case LS_RES_BT_va:
			RES_TO_ME_DRATIO(eff, pem->buattr.va.v);
		case LS_RES_BT_vaV:
			RES_TO_ME_DRATIO(eff, pem->buattr.va.dir);
		case LS_RES_BT_VHS:
			RES_TO_ME_DRATIO(eff, pem->buattr.vRate.ys);
		case LS_RES_BT_VWS:
			RES_TO_ME_DRATIO(eff, pem->buattr.vRate.xs);
		}
		return true;
	}
	static void laser_aceff_for(const action_eff_t* eff, void* flag)
	{
		csnode_t* pcs = (csnode_t*)flag;
		laser_t* pem = (laser_t*)pcs->pobj;
		// TODO
		ssize_t tmp = 0;
		switch (eff->type) {
			// 常规事件
		case LS_RES_T_X:
			pem->obj.ele.pos.x = action_res2(pem->obj.ele.pos.x, eff->ressign, eff->data);
			pem->obj.ele.flag = CSB_FLAG_TO(AUTO_SELF == pem->obj.ele.pos.x, pem->obj.ele.flag, X_AM);
			return;
		case LS_RES_T_Y:
			pem->obj.ele.pos.y = action_res2(pem->obj.ele.pos.y, eff->ressign, eff->data);
			pem->obj.ele.flag = CSB_FLAG_TO(AUTO_SELF == pem->obj.ele.pos.y, pem->obj.ele.flag, Y_AM);
			return;
		case LS_RES_T_r:
			CTL_LESS0_E0(pem->obj.emitedge.r, tmp, eff);
		case LS_RES_T_rV:
			pem->obj.emitedge.angle = action_res2(pem->obj.emitedge.angle, eff->ressign, eff->data);
			return;
		case LS_RES_T_Muzzle:
			CTL_LESS0_E0(pem->obj.nmuzzle, tmp, eff);
		case LS_RES_T_Freq:
			CTL_LESS0_E0(pem->obj.freq, tmp, eff);
		case LS_RES_T_Angle:
			if (AUTO_SELF == eff->data) {
				pem->obj.rotateOffset = AUTO_SELF;
				pem->obj.ele.flag |= R_AM;
			}
			else {
				pem->obj.rotateOffset = action_res2(pem->obj.rotateOffset, eff->ressign, eff->data);
			}
			pem->buattr.v.dir = pem->obj.rotateOffset;
			return;
		case LS_RES_T_Range:
			pem->obj.emitRange = action_res2(pem->obj.emitRange, eff->ressign, eff->data);
			return;
		case LS_RES_T_v:
			pem->obj.v.v = action_res2(pem->obj.v.v, eff->ressign, eff->data);
			return;
		case LS_RES_T_vV:
			pem->obj.v.dir = action_res2(pem->obj.v.dir, eff->ressign, eff->data);
			return;
		case LS_RES_T_va:
			pem->obj.va.v = action_res2(pem->obj.va.v, eff->ressign, eff->data);
			return;
		case LS_RES_T_vaV:
			pem->obj.va.dir = action_res2(pem->obj.va.dir, eff->ressign, eff->data);
			return;
		case LS_RES_BT_life:
			CTL_LESS0_E0(pem->buattr.lifetime, tmp, eff);
		case LS_RES_BT_ID:
			pem->buattr.ID = action_res2(pem->buattr.ID, eff->ressign, eff->data);
			return;
		case LS_RES_BT_WS:
			CTL_LESS0_E0(pem->buScale.xs, tmp, eff);
		case LS_RES_BT_HS:
			CTL_LESS0_E0(pem->buScale.ys, tmp, eff);


			//case LS_RES_BT_Alpha:
			//	CTL_COLOR_RES_DATA(pem->bucolor.A, tmp, eff);
			//	case LS_RES_T_Opdir:
			//	NOTE:朝向暂时不控制
		case LS_RES_BT_v:
			pem->buattr.v.v = action_res2(pem->buattr.v.v, eff->ressign, eff->data);
			return;
		case LS_RES_BT_vV:
			pem->buattr.v.dir = action_res2(pem->buattr.v.dir, eff->ressign, eff->data);
			return;
		case LS_RES_BT_va:
			pem->buattr.va.v = action_res2(pem->buattr.va.v, eff->ressign, eff->data);
			return;
		case LS_RES_BT_vaV:
			if (AUTO_SELF == eff->data) {
				pem->buattr.va.dir = AUTO_SELF;
				pem->obj.ele.flag |= RB_AM;
			}
			else {
				pem->buattr.va.dir = action_res2(pem->buattr.va.dir, eff->ressign, eff->data);
			}
			return;
		case LS_RES_BT_VHS:
			pem->buattr.vRate.ys = action_res2(pem->buattr.vRate.ys, eff->ressign, eff->data);
			return;
		case LS_RES_BT_VWS:
			pem->buattr.vRate.xs = action_res2(pem->buattr.vRate.xs, eff->ressign, eff->data);
			return;
			// 对于特效变化到0，就是关闭，否则就是开启

		case LS_RES_ET_Light:
			CTL_EFFECT_BY_RES_DATA(pem->bueffect, BU_EFF_Light, eff);
		case LS_RES_ET_OutSc:
			CTL_EFFECT_BY_RES_DATA(pem->bueffect, BU_EFF_OutSc, eff);
		case LS_RES_ET_Invin:
			CTL_EFFECT_BY_RES_DATA(pem->bueffect, BU_EFF_Invin, eff);
		}
	}

	static bool	 embu_action_match(const int8_t t, const int8_t s, const int d,
		const laserbu_t* pbu)
	{
		switch (t) {
		case LS_CON_T_NowFme:
			return action_con_match(pbu->b.attr.life, s, d);
		case LS_CON_T_X:
			return action_con_match(pbu->b.ele.pos.x, s, d);
		case LS_CON_T_Y:
			return action_con_match(pbu->b.ele.pos.y, s, d);
		default:
			return false;
		}
	}

	/* 处理发射器子弹的事件 */
	static bool	 laser_buac_for(action_t* pac, void* flag)
	{
		laserbu_t* pbu = (laserbu_t*)flag;
		// 判定条件是否触发
		bool b1 = embu_action_match(CON_GET_TYPE1(pac->con.tAs), CON_GET_SIGN1(pac->con.tAs), pac->con.data0, pbu);
		bool b2 = true;
		const int8_t aor = CON_GET_AOR(pac->con.tAs);
		if (CON_SIGN_TRUE != aor) {
			b2 = embu_action_match(CON_GET_TYPE2(pac->con.tAs), CON_GET_SIGN2(pac->con.tAs), pac->con.data1, pbu);
		}
		if (!action_2con_match(b1, b2, aor))
			return false;
		// 条件满足，进行处理
		action_eff_t* eff = action_make_action_eff(pac);
		CSB_NO_RET(eff, true);
		list_insert(&pbu->b.ac_eff_list, (void*)eff, 0, 0);
		// 如果是正比且变化符号是变化到，那么就需要转换成增量处理
		CSB_NO_RET(CON_RES_TO == eff->ressign && CON_ME_DRATIO == eff->mesign, true);
		eff->ressign = CON_RES_ADD;
		switch (pac->restype) {
		case LS_RES_BT_life:
			RES_TO_ME_DRATIO(eff, pbu->b.attr.lifetime);
		case LS_RES_BT_ID:
			RES_TO_ME_DRATIO(eff, pbu->b.attr.ID);
		case LS_RES_BT_WS:
			RES_TO_ME_DRATIO(eff, pbu->b.ele.scale.xs);
		case LS_RES_BT_HS:
			RES_TO_ME_DRATIO(eff, pbu->b.ele.scale.ys);

			//case LS_RES_BT_Alpha:
			//	RES_TO_ME_DRATIO(eff, pbu->color.A);
			//	case LS_RES_T_Opdir:
			//	NOTE:朝向暂时不控制
		case LS_RES_BT_v:
			RES_TO_ME_DRATIO(eff, pbu->b.attr.v.v);
		case LS_RES_BT_vV:
			RES_TO_ME_DRATIO(eff, pbu->b.attr.v.dir);
		case LS_RES_BT_va:
			RES_TO_ME_DRATIO(eff, pbu->b.attr.va.v);
		case LS_RES_BT_vaV:
			RES_TO_ME_DRATIO(eff, pbu->b.attr.va.dir);
		case LS_RES_BT_VHS:
			RES_TO_ME_DRATIO(eff, pbu->b.attr.vRate.ys);
		case LS_RES_BT_VWS:
			RES_TO_ME_DRATIO(eff, pbu->b.attr.vRate.xs);

		case LS_RES_ET_Light:
		case LS_RES_ET_OutSc:
		case LS_RES_ET_Invin:
			return true;
		}
		return true;
	}
	static void laserbu_aceff_for(const action_eff_t* eff, void* flag)
	{
		laserbu_t* pbu = (laserbu_t*)flag;
		ssize_t tmp = 0;
		switch (eff->type) {
		case LS_RES_BT_life:
			CTL_LESS0_E0(pbu->b.attr.lifetime, tmp, eff);
		case LS_RES_BT_ID:
			pbu->b.attr.ID = action_res2(pbu->b.attr.ID, eff->ressign, eff->data);
			return;
		case LS_RES_BT_WS:
			CTL_LESS0_E0(pbu->b.ele.scale.xs, tmp, eff);
		case LS_RES_BT_HS:
			CTL_LESS0_E0(pbu->b.ele.scale.ys, tmp, eff);
			//case LS_RES_BT_Alpha:
			//	CTL_COLOR_RES_DATA(pbu->color.A, tmp, eff);
			//case LS_RES_BT_Opdir:
			//	if (CSB_FLAG_TEST(pbu->effect, BU_EFF_Face2V))
			//		return;
			//	pbu->b.ele.rotate = action_res2(pbu->b.ele.rotate, eff->ressign, eff->data);
			//	return;
		case LS_RES_BT_v:
			pbu->b.attr.v.v = action_res2(pbu->b.attr.v.v, eff->ressign, eff->data);
			return;
		case LS_RES_BT_vV:
			pbu->b.attr.v.dir = action_res2(pbu->b.attr.v.dir, eff->ressign, eff->data);
			if (CSB_FLAG_TEST(pbu->effect, BU_EFF_Face2V))
				pbu->b.ele.rotate = pbu->b.attr.v.dir;
			return;
		case LS_RES_BT_va:
			pbu->b.attr.va.v = action_res2(pbu->b.attr.va.v, eff->ressign, eff->data);
			return;
		case LS_RES_BT_vaV:
			if (AUTO_SELF == eff->data) {
				pbu->b.attr.va.dir = AUTO_SELF;
				pbu->b.ele.flag |= RBRT_AM;
			}
			else {
				pbu->b.attr.va.dir = action_res2(pbu->b.attr.va.dir, eff->ressign, eff->data);
			}
			return;
		case LS_RES_BT_VHS:
			pbu->b.attr.vRate.ys = action_res2(pbu->b.attr.vRate.ys, eff->ressign, eff->data);
			return;
		case LS_RES_BT_VWS:
			pbu->b.attr.vRate.xs = action_res2(pbu->b.attr.vRate.ys, eff->ressign, eff->data);
			return;
			// 对于特效变化到0，就是关闭，否则就是开启

		case LS_RES_ET_Light:
			CTL_EFFECT_BY_RES_DATA(pbu->effect, BU_EFF_Light, eff);
		case LS_RES_ET_OutSc:
			CTL_EFFECT_BY_RES_DATA(pbu->effect, BU_EFF_OutSc, eff);
		case LS_RES_ET_Invin:
			CTL_EFFECT_BY_RES_DATA(pbu->effect, BU_EFF_Invin, eff);
		}
	}

	struct xyvlsm_t {
		int	userotate;
		float	rotate;
		v_t	v;
		v_t	va;
		scale_t	vRate;
	};

	/* 计算xy坐标系上的坐标增量 */
	static void	xy_vlsm(struct xyvlsm_t* p, pos_t* out)
	{
		float tmpvd = CSB_DEG2RAD(-p->v.dir);
		float tmpvad = CSB_DEG2RAD(-p->va.dir);
		float tmpv = p->v.v;
		if (1.0f != p->vRate.xs || 1.0f != p->vRate.ys) {
			const float radian = p->userotate ? CSB_DEG2RAD(-p->rotate) : tmpvd;
			tmpv = CSB_sqrt(CSB_pow(tmpv * CSB_sin(radian) * p->vRate.ys, 2)
				+ CSB_pow(tmpv * CSB_cos(radian) * p->vRate.xs, 2));
		}
		out->x = tmpv * CSB_cos(tmpvd) + p->va.v * CSB_cos(tmpvad) * 0.5f;
		out->y = tmpv * CSB_sin(tmpvd) + p->va.v * CSB_sin(tmpvad) * 0.5f;
		// 计算加速度对速度影响的合速度结果
		CSB_YES_VRET(0.0f == p->va.v);
		float anoffset = p->v.dir - p->va.dir;
		tmpvd = CSB_fabs(CSB_angle_normalize_180(anoffset));
		if (tmpvd < 0.01f) {
			// 加速度和速度方向相同
			p->v.v += p->va.v;
			if (p->v.v < 0) {
				p->v.v = -p->v.v;
				p->v.dir += 180.0f;
			}
			return;
		}
		if ((180.0f - tmpvd) < 0.1f) {
			// 加速度方向和速度方向相反
			p->v.v -= p->va.v;
			if (p->v.v < 0) {
				p->v.v = -p->v.v;
				p->v.dir += 180.0f;
			}
			return;
		}
		// 加速度方向和速度方向有夹角
		tmpv = p->v.v;
		float aa = tmpv * tmpv;
		float bb = p->va.v * p->va.v;

		float tmpangle = tmpvd - 90.0f;
		// 计算速度方向所在边对的角tmpvad
		if (ERROR_IS_TRUE(tmpangle, 0.01f)) {
			tmpvad = CSB_atan(p->va.v / tmpv);
			p->v.v = CSB_sqrt(aa + bb);
		}
		else {
			// 如果是锐角，那么应做加法，如果是钝角，那么应做减法
			tmpvd = tmpv * p->va.v * CSB_cos(CSB_DEG2RAD(tmpvd));
			p->v.v = CSB_sqrt(aa + bb + tmpvd + tmpvd);
			tmpvad = CSB_acos((aa + tmpvd) / (tmpv * p->v.v) - 0.0000013f);
		}
		// 得到了一个正锐角的加速度方向和新的速度方向的夹角，需要确定是加还是减
		tmpvd = CSB_RAD2DEG(tmpvad);
		if (CSB_angle_normalize_180(anoffset) < 0) {
			p->v.dir += tmpvd;
		}
		else {
			p->v.dir -= tmpvd;
		}
	}


/*********************| extern functions |*********************/

CSB_DLL csobjdata_t* laserdata_read(unsigned char* data, const uint32_t totalframe)
{
	ZERO_MALLOC(pem, laserdata_t);
	// read csobj_t data len
	pem->objtag.totalframe = totalframe;
	uint32_t offset = sizeof(csobjdata_t)-sizeof(totalframe);
	memcpy((unsigned char*)(&pem->objtag) + sizeof(totalframe), data, offset);
	if (pem->objtag.fe > pem->objtag.totalframe) {
		pem->objtag.fe = pem->objtag.totalframe;
	}
	// read
	//memcpy(&pem->emitpos, data + offset, sizeof(pem->emitpos));
	//offset += sizeof(pem->emitpos);
	//memcpy(&pem->emitPosVar, data + offset, sizeof(pem->emitPosVar));
	//offset += sizeof(pem->emitPosVar);
	// read action
	offset += actiondata_read(&pem->aclist, data + offset, 0);
	// read bullet
	memcpy(&pem->bullet, data + offset, sizeof(laserbudata_t)-sizeof(ac_t));
	uint32_t v = sizeof(laserbudata_t);
	uint32_t vi = sizeof(ac_t);
	offset +=v-vi;

	actiondata_read(&pem->bullet.aclist, data + offset, LS_OBJ_BULLET_ACTION_BOUNDARY);
	return (csobjdata_t*)pem;
}

CSB_DLL laser_t* laserdata_make_obj(const csobjdata_t* pdata)
{
	const laserdata_t* pem = (const laserdata_t*)pdata;
	laser_t* ret = laser_buf_rent();
	laser_2origin(pem, ret, false);
	ret->obj.life = 0;
	return ret;
}

CSB_DLL void laserdata_free(csobjdata_t* plaser)
{
	laserdata_t* pem = (laserdata_t*)plaser;
	CSB_LOG("%s laser was released\n", pem->objtag.name);
	ac_free(pem->aclist);
	ac_free(pem->bullet.aclist);
	free(pem);
}


CSB_DLL void laser_buf_init()
{
	CS_BUF_INIT(laserbu_t);
	CS_BUF_INIT(laser_t);
}

CSB_DLL void laser_buf_end(bool force)
{
	CS_BUF_END(laser_t, force);
	CS_BUF_END(laserbu_t, force);
}

CSB_DLL laser_t* laser_buf_rent()
{
	CS_BUF_RENT(laser_t, ret);
	return ret;
}

CSB_DLL void laser_buf_return(laser_t* pla) {

		CS_BUF_RETURN(laser_t, pla);
		ac_free(pla->aclist);
		action_eff_list_clean(&pla->obj.ac_eff_list);
}
static int	laser_bu_update(void** datare, void* ctldata)
{
	laserbu_t* pe = (laserbu_t*)(*datare);
	csnode_t* pcs = (csnode_t*)ctldata;
	// 判定生命是否结束
	++pe->b.attr.life;
	if (pe->b.attr.life >= pe->b.attr.lifetime) {
		if (pcs->cbs.on_budead) {
			pcs->cbs.on_budead((bullet_t*)pe, pcs->cbs.udata);
		}
		laserbu_buf_return(pe);
		return BULLET_UPDATE_DEAD; \

	}
	ac_foreach(pe->aclist, laser_buac_for, pe->b.attr.life, (void*)pe);
	action_eff_list_for(&pe->b.ac_eff_list, laserbu_aceff_for, (void*)pe);
	// 加速度方向的自机
	if (CSB_FLAG_TEST(pe->b.ele.flag, RBRT_AM) && pcs->cbs.on_am) {
		pe->b.attr.va.dir = CSB_rotate_p2p(&pe->b.ele.pos, &pcs->cbs.autoPos);
	}
	// 调整子弹坐标
	pos_t offset;
	struct xyvlsm_t vlsmt = { 0, 0, pe->b.attr.v, pe->b.attr.va, pe->b.attr.vRate };
	xy_vlsm(&vlsmt, &offset);

	pe->b.attr.v = vlsmt.v;
	CSB_LOG("BU_EFF_Face2V is %u\n", BU_EFF_Face2V);
	CSB_LOG("effect is %u\n", pe->effect);
	if (CSB_FLAG_TEST(pe->effect, BU_EFF_Face2V))
		pe->b.ele.rotate = vlsmt.v.dir;
	pe->b.ele.pos.x += offset.x;
	pe->b.ele.pos.y -= offset.y;
	pe->b.ele.rotate = vlsmt.v.dir;
	// 判定出屏即消
	if (CSB_FLAG_TEST(pe->effect, BU_EFF_OutSc) && CSB_OUT_SCREEN(pe->b.ele.pos)) {
		float lx = _csb_screen.lx;
		float rx = _csb_screen.rx;
		float ly = _csb_screen.ly;
		float ry = _csb_screen.ry;
		if (pcs->cbs.on_budead) {
			pcs->cbs.on_budead((bullet_t*)pe, pcs->cbs.udata);
		}
		laserbu_buf_return(pe);
		return BULLET_UPDATE_DEAD;
	}
	if (pcs->cbs.on_buupdate) {
		int ret = pcs->cbs.on_buupdate((bullet_t*)pe, pcs->cbs.udata);
		if (BULLET_UPDATE_DEAD == ret) {
			if (pcs->cbs.on_budead) {
				pcs->cbs.on_budead((bullet_t*)pe, pcs->cbs.udata);

			}
			laserbu_buf_return(pe);
		}
		return ret;
	}
	return BULLET_UPDATE_CONTINUE;
}


CSB_DLL void laser_emit(csnode_t* pcsn)
{
	laserdata_t* src = (laserdata_t*)pcsn->pobjdata;
	laser_t* pem = (laser_t*)pcsn->pobj;
	// 确定发射多少枚子弹
	const int32_t nmuzzle = pem->obj.nmuzzle + RAND_VAR_INT(src->objtag.nmuzzleVar);
	if (nmuzzle <= 0) return;
	// 三个用于发射角度计算的常量
	const float C = (float)(pem->obj.emitRange + RAND_VAR_INT(src->objtag.emitrangeVar)) / nmuzzle;
	const float halfC = (nmuzzle % 2) ? 0 : (C / 2);
	const float sangle = RAND_VAR(src->objtag.angleVar);
	const float amend = ((nmuzzle - 1) / 2) * C;
	// 随机速度
	const float tv = pem->buattr.v.v + RAND_VAR(src->bullet.b.vVar);
	if (CSB_FLAG_TEST(pem->obj.ele.flag, RB_AM) && pcsn->cbs.on_am) {
		pem->buattr.va.dir = CSB_rotate_p2p(&pem->obj.ele.pos, &pcsn->cbs.autoPos);
	}
	const v_t va = { pem->buattr.va.v + RAND_VAR(src->bullet.b.vaVar.v),
		pem->buattr.va.dir + RAND_VAR(src->bullet.b.vaVar.dir) };
	//发射范围, 和弧度确定, 随机半径
	const float tmpRan = pem->obj.emitedge.angle + RAND_VAR(src->objtag.emitedgeVar.angle);
	const float tmpr = pem->obj.emitedge.r + RAND_VAR(src->objtag.emitedgeVar.r);
	// 随机发射位置
	const pos_t emitPos = { pem->obj.ele.pos.x + RAND_VAR(src->emitPosVar.x),
		pem->obj.ele.pos.y + RAND_VAR(src->emitPosVar.y) };

	float radian = 0;//弧度缓冲
	float matht = 0; // 三角函数缓冲
	int32_t i = 0;
	//首先求出来发射坐标，如果有出屏即消除，又不在屏幕内，那么不发射
	float tmpVDir;
	pos_t tmpPos;
	while (i < nmuzzle) {
		tmpVDir = halfC - i * C + sangle + amend;
		++i;
		radian = CSB_DEG2RAD(-(tmpVDir + tmpRan));
		matht = CSB_sin(radian);
		tmpPos.y = -(tmpr * matht) + emitPos.y;
		matht = CSB_cos(radian);
		tmpPos.x = (tmpr * matht) + emitPos.x;
		if (CSB_FLAG_TEST(pem->bueffect, BU_EFF_OutSc) && CSB_OUT_SCREEN(tmpPos)) {
			continue;
		}
		CS_BUF_RENT(laserbu_t, ret);
		CSB_NO_VRET(ret);
		ret->b.udata = NULL;
		ret->b.attr.v.dir = CSB_fmod((tmpVDir + pem->buattr.v.dir), 360.0f);
		ret->b.ele.pos = tmpPos;
		ret->b.ele.flag = 0;
		//发射范围, 和弧度确定
		ret->b.attr.v.v = tv;
		ret->b.attr.vRate = pem->buattr.vRate;
		ret->b.attr.va = va;
		ret->b.attr.ID = pem->buattr.ID;
		ret->b.attr.life = 0;
		ret->b.attr.lifetime = pem->buattr.lifetime;
		ret->b.ele.scale = pem->buScale;
		//NOTE:受到加速度的控制
		ret->b.ele.rotate = ret->b.attr.v.dir;
		//ret->color = pem->bucolor;
		ret->effect = pem->bueffect;
		ret->aclist = ac_buf_copy(src->bullet.aclist);
		// add to bulist
		list_insert(&pcsn->bulist, (void*)ret, 0, 0);
		// call on buborn
		if (pcsn->cbs.on_buborn) {
			pcsn->cbs.on_buborn((bullet_t*)ret, pcsn->cbs.udata);
		}
	}
}

CSB_DLL void laser_update(csnode_t* pcsn, bool updateObj, bool updateBullet)
{
	laser_t* em = (laser_t*)pcsn->pobj;
	// 元素事件处理
	if (1 == pcsn->nframe && em->obj.life > 1) {
		laser_2origin((laserdata_t*)pcsn->pobjdata, em, true);
	}
	if (updateObj) {
		ac_foreach(em->aclist, laser_ac_for, pcsn->nframe, pcsn);
		// 遍历事件结果队列加成
		action_eff_list_for(&em->obj.ac_eff_list, laser_aceff_for, (void*)pcsn);
		// NOTE:自机的处理
		if (NO_BODY_SELF(em->obj.ele.pos) && CSB_FLAG_TEST(em->obj.ele.flag, R_AM) && pcsn->cbs.on_am) {
			em->obj.rotateOffset = CSB_rotate_p2p(&em->obj.ele.pos, &pcsn->cbs.autoPos);
		}
		// 调整坐标，
		struct xyvlsm_t vlsmt = { 1, em->obj.ele.rotate, em->obj.v, em->obj.va, { 1.0f, 1.0f } };
		pos_t offset;
		xy_vlsm(&vlsmt, &offset);
		em->obj.v = vlsmt.v;
		em->obj.ele.pos.x += offset.x;
		em->obj.ele.pos.y -= offset.y;
		if (pcsn->cbs.on_objupdate) {
			pcsn->cbs.on_objupdate(pcsn->pobj, pcsn->cbs.udata);
		}
	}
	if (updateBullet) {
		list_foreach(&pcsn->bulist, laser_bu_update, pcsn);
	}
}

CSB_DLL void laserbu_buf_return(laserbu_t* pbu) {
	CS_BUF_RETURN(laserbu_t, pbu);
	ac_free(pbu->aclist);
	action_eff_list_clean(&pbu->b.ac_eff_list);

}






#ifdef __cplusplus
} /* end extern C */
#endif
